/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.designschema.generator;

import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.cef.api.RefObject;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.nocode.BusinessField;
import com.inspur.edp.udt.designtime.api.nocode.IBusinessFieldService;
import com.inspur.edp.web.common.environment.ExecuteEnvironment;
import com.inspur.edp.web.common.metadata.MetadataGetterParameter;
import com.inspur.edp.web.common.metadata.MetadataTypeEnum;
import com.inspur.edp.web.common.metadata.MetadataUtility;
import com.inspur.edp.web.common.utility.StringUtility;
import com.inspur.edp.web.designschema.elements.ComplexField;
import com.inspur.edp.web.designschema.elements.Field;
import com.inspur.edp.web.designschema.elements.SimpleField;
import com.inspur.edp.web.designschema.elements.editor.*;
import com.inspur.edp.web.designschema.elements.type.EntityType;
import com.inspur.edp.web.designschema.elements.type.FieldType;
import com.inspur.edp.web.designschema.elements.type.ObjectType;
import com.inspur.edp.web.designschema.udtextensiondef.FormUdtExtension;
import io.iec.edp.caf.commons.exception.CAFRuntimeException;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 字段构造
 *
 * @author noah
 */
public class FieldBuilder {
    private final FieldTypeBuilder fieldTypeBuilder;

    public FieldBuilder() {
        this.fieldTypeBuilder = new FieldTypeBuilder(this);
    }

    /**
     * 运行时定制也进行了调用 不可随意更改参数及方法名大小写
     *
     * @param element
     * @param parentTypeBuildingContext
     * @param scene
     * @return
     */
    public final Field build(IGspCommonField element, TypeBuildingContext parentTypeBuildingContext, String scene) {
        TypeBuildingContext elementContext = TypeBuildingContext.Create(element, parentTypeBuildingContext);
        return this.build(elementContext, parentTypeBuildingContext, scene);
    }

    public final Field build(GspViewModelElement element, TypeBuildingContext parentTypeBuildingContext, String scene, boolean isRuntime) {
        TypeBuildingContext elementContext = TypeBuildingContext.Create(element, parentTypeBuildingContext, isRuntime);
        return this.build(elementContext, parentTypeBuildingContext, scene);
    }

    /**
     * 保留此方法  运行时定制会进行调用
     *
     * @param element
     * @param parentTypeBuildingContext
     * @param scene
     * @return
     */
    public final Field build(GspViewModelElement element, TypeBuildingContext parentTypeBuildingContext, String scene) {
        TypeBuildingContext elementContext = TypeBuildingContext.Create(element, parentTypeBuildingContext);
        return this.build(elementContext, parentTypeBuildingContext, scene);
    }

    public final Field build(SimpleDataTypeDef element, TypeBuildingContext parentTypeBuildingContext, String scene) {
        TypeBuildingContext elementContext = TypeBuildingContext.Create(element, parentTypeBuildingContext);
        return this.build(elementContext, parentTypeBuildingContext, scene);
    }

    public Field build(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext, String scene) {
        String bindingFieldPrefix = this.getBindingFieldPrefix(parentTypeBuildingContext);
        String id = elementContext.Get("Id", String.class);
        String code = elementContext.Get("Code", String.class);
        String name = elementContext.Get("Name", String.class);
        String label = elementContext.Get("Label", String.class);
        boolean multiLanguageInput = elementContext.<Boolean>Get("MultiLanguageInput", Boolean.class);

        String generatedBindingField = String.format("%1$s%2$s", bindingFieldPrefix, label);
        elementContext.getParams().put("BindingField", generatedBindingField);


        String revisedElementId = elementContext.ReviseElementId(id);
        elementContext.getParams().put("Id", revisedElementId);

        String generatedFieldPath = this.generateFieldPath(elementContext, parentTypeBuildingContext);
        elementContext.getParams().put("Path", generatedFieldPath);

        String generatedBindingPath = this.GenerateBindingPath(elementContext, parentTypeBuildingContext);
        elementContext.getParams().put("BindingPath", generatedBindingPath);

        if (elementContext.getHasAssociation() || elementContext.getHasUnifiedDataType() || elementContext.getIsDynamicField()) {
            ComplexField tempVar = new ComplexField();
            tempVar.setId(revisedElementId);
            tempVar.setOriginalId(id);
            tempVar.setCode(code);
            tempVar.setName(name);
            tempVar.setLabel(StringUtility.toCamelCase(label));
            tempVar.setBindingField(StringUtility.toCamelCase(generatedBindingField));
            tempVar.setPath(generatedFieldPath);
            tempVar.setBindingPath(generatedBindingPath);
            tempVar.setType(this.fieldTypeBuilder.GenerateFieldType(elementContext, parentTypeBuildingContext, scene));
            if (elementContext != null && elementContext.getHasUnifiedDataType() && !elementContext.getIsRefElement()) {
                this.handleUdtExtend(tempVar, elementContext);
            } else if (elementContext != null && elementContext.getHasBusiFieldId() && !elementContext.getIsRefElement()) {
                this.handleBusiFieldExtent(tempVar, elementContext);
            }
            return tempVar;
        }
        boolean require = elementContext.<Boolean>Get("Require", Boolean.class);
        String defaultValue = elementContext.Get("DefaultValue", String.class);
        boolean isReadOnly = elementContext.<Boolean>Get("Readonly", Boolean.class);
        SimpleField tempVar2 = new SimpleField();
        tempVar2.setId(revisedElementId);
        tempVar2.setOriginalId(id);
        tempVar2.setCode(code);
        tempVar2.setName(name);
        tempVar2.setLabel(StringUtility.toCamelCase(label));
        tempVar2.setBindingField(StringUtility.toCamelCase(generatedBindingField));
        tempVar2.setPath(generatedFieldPath);
        tempVar2.setBindingPath(generatedBindingPath);
        tempVar2.setRequire(require);
        tempVar2.setReadonly(isReadOnly);
        tempVar2.setDefaultValue(defaultValue);
        tempVar2.setMultiLanguage(multiLanguageInput);
        tempVar2.setType(this.fieldTypeBuilder.GenerateFieldType(elementContext, parentTypeBuildingContext, scene));
        tempVar2.setEditor(this.GenerateFieldEditor(elementContext, scene));
        return tempVar2;
    }

    protected final String getBindingFieldPrefix(TypeBuildingContext context) {
        String prefix = "";

        if (context != null) {
            String bindingField = context.Get("BindingField", String.class);
            if (bindingField != null) {
                prefix = String.format("%1$s_", bindingField);
            }
        }
        return prefix;
    }


    protected final String generateFieldPath(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext) {
        return generateFieldPath(elementContext, parentTypeBuildingContext, false);
    }

    //C# TO JAVA CONVERTER NOTE: Java does not support optional parameters. Overloaded method(s) are created above:
//ORIGINAL LINE: protected string GenerateFieldPath(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext, bool toCamel = false)
    protected final String generateFieldPath(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext, boolean toCamel) {
        String fieldPath = elementContext.Get("Label", String.class);
        // 如果已经在Context中预制了BindingPath，直接返回预制结果。
        // 适用于BE关联类型字段中存储自身值的特殊字段场景。
        String presetPath = elementContext.Get("Path", String.class);
        if (elementContext.getHasPresetValue() && !StringUtility.isNullOrEmpty(presetPath)) {
            fieldPath = presetPath;
        }
        //var label = elementContext.Get<string>("Label");
        if (toCamel) {
            fieldPath = StringUtility.toCamelCase(fieldPath);
        }
        String prefix = "";
        if (parentTypeBuildingContext != null) {
            prefix = parentTypeBuildingContext.Get("Path", String.class);
        }
        if (!StringUtility.isNullOrEmpty(prefix)) {
            return String.format("%1$s.%2$s", prefix, fieldPath);
        }
        return fieldPath;
    }

    protected final String GenerateBindingPath(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext) {
        String label = StringUtility.toCamelCase(elementContext.Get("Label", String.class));
        // 如果已经在Context中预制了BindingPath，直接返回预制结果。
        // 适用于BE关联类型字段中存储自身值的特殊字段场景。
        String presetBindingPath = elementContext.Get("BindingPath", String.class);
        if (elementContext.getHasPresetValue() && !StringUtility.isNullOrEmpty(presetBindingPath)) {
            label = presetBindingPath;
        }

        String prefix = "";
        if (parentTypeBuildingContext != null) {
            prefix = parentTypeBuildingContext.Get("BindingPath", String.class);
        }
        if (!StringUtility.isNullOrEmpty(prefix)) {
            return String.format("%1$s.%2$s", prefix, label);
        }
        return label;
    }

    protected final FieldEditor GenerateFieldEditor(TypeBuildingContext context, String scene) {
        if (context.getObjectType() == GspElementObjectType.Enum) {
            return new EnumField();
        } else if (context.getIsMultiLanguageField()) {
            return new LanguageTextBox();
        } else if (context.getObjectType() == GspElementObjectType.None) {
            switch (context.getDataType()) {
                case Boolean:
                    if (!StringUtility.isNullOrEmpty(scene) && "mobile".equals(scene)) {
                        return new SwitchField();
                    }
                    return new CheckBox();
                case Date:
                case DateTime:
                    DateBox tempVar = new DateBox();
                    tempVar.setFormat("'yyyy-MM-dd'");
                    return tempVar;
                case Decimal:
                case Integer:
                    return new NumericBox();
                case Text:
                    return new MultiTextBox();
                default:
                    return new TextBox();
            }
        } else {
            return new TextBox();
        }
    }

    /**
     *
     */
    private void handleBusiFieldExtent(ComplexField bizField, TypeBuildingContext elementContext) {
        FormUdtExtension extendProperty = elementContext.Get("ExtendBusiFieldProp", FormUdtExtension.class);
        if (extendProperty == null) {
            return;
        }

        String beBindingFieldId = extendProperty.getControlBindingFieldId();
        if (beBindingFieldId == null) {
            return;
        }

        EntityType entityType = (EntityType) bizField.getType();
        if (entityType == null || entityType.getFields().size() == 0) {
            return;
        }

        Map<String, String> bizFieldsMap = getBizFieldMap(bizField);
        IGspCommonField helpField = null;
        if (bizField != null && !bizFieldsMap.isEmpty()) {
            // 需要找出业务字段对应的实体上的原本字段。
            RefObject<Field> schemaFieldRef = new RefObject<>(null);
            String schemaBindingFieldId = transferBindingFieldId(beBindingFieldId, bizField, elementContext, schemaFieldRef);
//            List<GspAssociation> associations = elementContext.getAssociations();
//            if (associations != null && associations.size() > 0) {
//                GspAssociation gspAssociation = associations.get(0);
//                if (gspAssociation != null) {
//                    List<IGspCommonField> refElementCollections = gspAssociation.getRefElementCollection();
//                    if (refElementCollections != null && refElementCollections.size() > 0) {
//                        helpField = refElementCollections.stream().filter(item -> {
//                            return beBindingFieldId.equals(item.getRefElementId());
//                        }).findFirst().orElse(null);
//                    }
//                }
//            }
//            if (helpField != null) {
//                List<Field> childAssoFields = entityType.getFields();
//                for (int i = 0; i < childAssoFields.size(); i++) {
//                    Field field = childAssoFields.get(i);
//                    if (helpField.getID().equals(field.getId())) {
//                        setBusiFieldEditor(field, extendProperty, elementContext, bizFieldsMap);
//                        break;
//                    }
//                }
//            }
            if (schemaBindingFieldId != null) {
                setBusiFieldEditor(schemaFieldRef.argvalue, extendProperty, elementContext, bizFieldsMap);
            }
        }
    }

    private Map<String, String> getBizFieldMap(ComplexField complexField) {
        Map<String, String> bizFieldsMap = new HashMap<>();
        FieldType type = complexField.getType();
        List<Field> children = new ArrayList<>();
        if (type instanceof ObjectType) {
            children = ((ObjectType) type).getFields();
        } else if (type instanceof EntityType) {
            children = ((EntityType) type).getFields();
        }
        if (children != null && children.size() > 0) {
            List<Field> finalChildren = children;
            Queue<Field> queue = new LinkedList<Field>() {{
                addAll(finalChildren);
            }};

            while (!queue.isEmpty()) {
                Field field = queue.poll();
                bizFieldsMap.put(field.getCode(), field.getBindingPath());
                if (field instanceof ComplexField) {
                    FieldType childType = field.getType();
                    if (childType instanceof ObjectType) {
                        List<Field> childFields = ((ObjectType) childType).getFields();
                        for (Field childField : childFields) {
                            childField.setCode(field.getCode() + '.' + childField.getCode());
                        }
                        queue.addAll(childFields);
                    } else if (childType instanceof EntityType) {
                        List<Field> childFields = ((EntityType) childType).getFields();
                        for (Field childField : childFields) {
                            childField.setCode(field.getCode() + '.' + childField.getCode());
                        }
                        queue.addAll(childFields);
                    }
                }
            }
        }

        return bizFieldsMap;

    }

    private void setBusiFieldEditor(Field helpField, FormUdtExtension extendProperty, TypeBuildingContext elementContext, Map<String, String> bizFieldsMap) {
        GspViewModelElement belongedElement = elementContext.Get("Element", GspViewModelElement.class);
        String objCode;
        if (belongedElement == null) {
            // 增加从BelongObjectCode中获取参数的方式主要是为了零代码 不存在对应的vo element情况
            // 优先仍然采用从对应的viewModelElement中获取的形式
            objCode = elementContext.Get("BelongObjectCode", String.class);
        } else {
            objCode = belongedElement.getBelongObject().getCode();
        }
        String uri = String.format("%1$s.%2$s", objCode, helpField.getBindingField());
        String displayName = extendProperty.getLookupConfig().getDisplayName();
        String idField = extendProperty.getLookupConfig().getIdField();
        String dataSourceType = "ViewObject";
        DataSource dataSource = new DataSource() {{
            this.setUri(uri);
            this.setDisplayName(displayName);
            this.setIdField(idField);
            this.setType(dataSourceType);
        }};
        LookupEdit editor = new LookupEdit();

        String controlType = extendProperty.getControlType();
        if (!StringUtils.isEmpty(controlType)) {
            editor.set$type(controlType);
        }

        editor.setDataSource(dataSource);

        String valueField = extendProperty.getLookupConfig().getValueField();
        editor.setValueField(valueField);

        String textField = extendProperty.getLookupConfig().getTextField();
        editor.setTextField(textField);

        String helpId = extendProperty.getLookupConfig().getHelpId();
        editor.setHelpId(helpId);
        String helpDisplayType = extendProperty.getLookupConfig().getDisplayType();
        editor.setDisplayType(helpDisplayType);
        HashMap<String, String> mapFieldsNode = extendProperty.getLookupConfig().getMapFields();
        String rootFieldName = elementContext.Get("BindingPath", String.class);
        HashMap<String, String> mapFields = new HashMap<>();
        if (mapFieldsNode != null) {
            Iterator<String> keys = mapFieldsNode.keySet().iterator();
            while (keys.hasNext()) {

                String key = keys.next();
                String fieldPathInUdt = mapFieldsNode.get(key);
                String bindingPath = bizFieldsMap.get(fieldPathInUdt);
                // 没有转换后的名称说明扩展属性里的信息有误，跳过。
                if (bindingPath != null) {
                    mapFields.put(key, bindingPath);
                }
            }
            mapFields.put("id", rootFieldName + "." + rootFieldName);
        }
        editor.setMap(mapFields);

        ((SimpleField) helpField).setEditor(editor);
    }

    /**
     * 处理udt上的扩展属性，根据扩展属性修正关联字段的editor属性
     *
     * @param udtField       Udt业务字段
     * @param elementContext 类型构建上下文
     */
    private void handleUdtExtend(ComplexField udtField, TypeBuildingContext elementContext) {
        if (!elementContext.getHasUnifiedDataType()) {
            return;
        }

        FormUdtExtension extendProperty = elementContext.Get("ExtendProperty", FormUdtExtension.class);
        if (extendProperty == null) {
            return;
        }

        String lookupBindingFiledId = extendProperty.getControlBindingFieldId();
        if (lookupBindingFiledId == null) {
            return;
        }

        ObjectType entityType = (ObjectType) udtField.getType();
        if (entityType == null || entityType.getFields().size() == 0) {
            return;
        }

        Map<String, String> udtFieldsMap = new HashMap<>();
        UdtFieldTreeNode udtFieldNode = new UdtFieldTreeNode(udtField, null);
        collectUdtSchemaFields(udtFieldsMap, udtFieldNode, udtField);

        String[] lookupBindingFieldIds = lookupBindingFiledId.split(",");
        if (lookupBindingFieldIds.length == 0) {
            return;
        }
        UdtFieldTreeNode currentNode = udtFieldNode;
        /*
         * 1. 关联型udt：     field - object - list  object id为udt id
         * 2. 非关联单值udt：  field - field2         field2 id为udt id
         * 3. 多值udt：       field - list           schema结构中没有udt id
         */
        String udtId = elementContext.getUnifiedDataType();
        UdtFieldTreeNode udtObjectNode = udtFieldNode.getChild(udtId);
        if (udtObjectNode != null) {
            currentNode = udtObjectNode;
        }
        int cursor = 0;
        if (udtId.equals(lookupBindingFieldIds[0])) {
            cursor = 1;
        }
        for (; cursor < lookupBindingFieldIds.length; cursor++) {
            String fieldId = lookupBindingFieldIds[cursor];
            currentNode = currentNode.getChild(fieldId);
            if (currentNode == null) {
                return;
            }
        }

        Field lookupBindingField = currentNode.getField();
        // 指定的关联字段不是简单字段，无法修改editor属性，退出
        if (!(lookupBindingField instanceof SimpleField)) {
            return;
        }

        // 处理的当前字段是帮助指定的显示字段，当前字段的默认editor指定为LookupEdit
        LookupEdit editor = new LookupEdit();

        String controlType = extendProperty.getControlType();
        if (!StringUtils.isEmpty(controlType)) {
            editor.set$type(controlType);
        }

        String bindingField = lookupBindingField.getBindingField();
        GspViewModelElement belongedElement = elementContext.Get("Element", GspViewModelElement.class);
        String objCode;
        if (belongedElement == null) {
            // 增加从BelongObjectCode中获取参数的方式主要是为了零代码 不存在对应的vo element情况
            // 优先仍然采用从对应的viewModelElement中获取的形式
            objCode = elementContext.Get("BelongObjectCode", String.class);
        } else {
            objCode = belongedElement.getBelongObject().getCode();
        }
        if (StringUtils.isEmpty(objCode)) {
            return;
        }
        // String objectCode = belongedElement.getBelongObject().getCode();
        String uri = String.format("%1$s.%2$s", objCode, bindingField);
        String displayName = extendProperty.getLookupConfig().getDisplayName();
        String idField = extendProperty.getLookupConfig().getIdField();
        String dataSourceType = "ViewObject";
        DataSource dataSource = new DataSource() {{
            this.setUri(uri);
            this.setDisplayName(displayName);
            this.setIdField(idField);
            this.setType(dataSourceType);
        }};
        editor.setDataSource(dataSource);

        String valueField = extendProperty.getLookupConfig().getValueField();
        editor.setValueField(valueField);

        String textField = extendProperty.getLookupConfig().getTextField();
        editor.setTextField(textField);

        String helpId = extendProperty.getLookupConfig().getHelpId();
        editor.setHelpId(helpId);
        String helpDisplayType = extendProperty.getLookupConfig().getDisplayType();
        editor.setDisplayType(helpDisplayType);
        HashMap<String, String> mapFields = new HashMap<>();
        HashMap<String, String> mapFieldsNode = extendProperty.getLookupConfig().getMapFields();
        if (mapFieldsNode != null) {
            Iterator<String> keys = mapFieldsNode.keySet().iterator();
            while (keys.hasNext()) {
                String key = keys.next();
                String fieldPathInUdt = mapFieldsNode.get(key);
                String fieldPath = udtField.getPath() + "." + fieldPathInUdt;
                String transformValue = udtFieldsMap.get(fieldPath);
                // 没有转换后的名称说明扩展属性里的信息有误，跳过。
                if (transformValue != null) {
                    mapFields.put(key, transformValue);
                }
            }
        }

        editor.setMap(mapFields);
        editor.setOptions(extendProperty.getLookupConfig().getOptions());

        ((SimpleField) lookupBindingField).setEditor(editor);
    }

    private void collectUdtSchemaFields(Map<String, String> fieldsMap, UdtFieldTreeNode fieldNode, ComplexField complexField) {
        FieldType type = complexField.getType();
        List<Field> children;
        if (type instanceof ObjectType) {
            children = ((ObjectType) type).getFields();
        } else if (type instanceof EntityType) {
            children = ((EntityType) type).getFields();
        } else {
            return;
        }
        for (Field childField : children) {
            fieldsMap.put(childField.getPath(), childField.getBindingPath());
            UdtFieldTreeNode childFieldNode = new UdtFieldTreeNode(childField, fieldNode);
            if (childField instanceof ComplexField) {
                collectUdtSchemaFields(fieldsMap, childFieldNode, (ComplexField) childField);
            }
        }
    }


    private enum BeFieldGenType {
        Origin,
        Single,
        Multi,
        Relation
    }

    private String transferBindingFieldId(String beBindingFieldId, ComplexField bizField, TypeBuildingContext elementContext, RefObject refObject) {
        Objects.requireNonNull(beBindingFieldId, "beBindingFieldId不能为空");
        // 找到业务字段
        // IBusinessFieldService businessFieldService = SpringBeanUtils.getBean(IBusinessFieldService.class);
        // BusinessField businessField = businessFieldService.getBusinessField(elementContext.getBusinessFieldId());
        BusinessField businessField = elementContext.getBusinessFieldInstance();
        // 找到be
        // GspAssociationCollection associations = (GspAssociationCollection) businessField.getUnifiedDataTypeDef().getPropertys().getPropertyName("ChildAssociations").getPropertyValue();
        // String bizFieldBeId = associations.get(0).getRefModelID();

        String bizFieldBeId = businessField.getAssoInfo().getRefModelID();
        GspMetadata beMeta = getMetadata(bizFieldBeId, elementContext.isRuntime());
        GspBusinessEntity be = (GspBusinessEntity) beMeta.getContent();
        // 找到be上的字段
        GspBizEntityElement beField = null;
        GspBizEntityElement beParentField = null;
        BeFieldGenType fieldGenType = BeFieldGenType.Origin;
        GspBizEntityObject mainObject = be.getMainObject();
        for (IGspCommonField element : mainObject.getContainElements()) {
            if (beBindingFieldId.equals(element.getID())) {
                beField = (GspBizEntityElement) element;
                fieldGenType = BeFieldGenType.Origin;
                break;
            }
            if (element.getHasAssociation()) {
                for (GspAssociation association : element.getChildAssociations()) {
                    for (IGspCommonField refElement : association.getRefElementCollection()) {
                        if (beBindingFieldId.equals(refElement.getID())) {
                            beField = (GspBizEntityElement) refElement;
                            beParentField = (GspBizEntityElement) element;
                            fieldGenType = BeFieldGenType.Relation;
                            break;
                        }
                    }
                }
            } else if (element.getChildElements().size() > 0) {
                for (IGspCommonField childElement : element.getChildElements()) {
                    if (beBindingFieldId.equals(childElement.getID())) {
                        beField = (GspBizEntityElement) childElement;
                        beParentField = (GspBizEntityElement) element;
                        fieldGenType = element.getChildElements().size() == 1 ? BeFieldGenType.Single : BeFieldGenType.Multi;
                        break;
                    }
                }
            }
        }
        Objects.requireNonNull(beField, "未在实体上找到对应的字段，请检查业务字段配置信息");
        // 根据字段的belongField，判断类型： 1. 单值  2. 多值   3.关联

        switch (fieldGenType) {
            case Origin:
                // 0. 原生字段
                IGspCommonField helpField = null;
                EntityType entityType = (EntityType) bizField.getType();
                List<GspAssociation> contextAssociations = elementContext.getAssociations();
                if (contextAssociations != null && contextAssociations.size() > 0) {
                    GspAssociation gspAssociation = contextAssociations.get(0);
                    if (gspAssociation != null) {
                        List<IGspCommonField> refElementCollections = gspAssociation.getRefElementCollection();
                        if (refElementCollections != null && refElementCollections.size() > 0) {
                            helpField = refElementCollections.stream().filter(item -> beBindingFieldId.equals(item.getRefElementId())).findFirst().orElse(null);
                        }
                    }
                }
                if (helpField != null) {
                    List<Field> childAssoFields = entityType.getFields();
                    for (Field field : childAssoFields) {
                        if (helpField.getID().equals(field.getId())) {
                            refObject.argvalue = field;
                            break;
                        }
                    }
                }
                return helpField.getID();
            case Single:
                // 1. 单值
            case Multi:
                // 2. 多值

                GspBizEntityElement finalBeParentField = beParentField;
                IGspCommonField voParentField = elementContext.getAssociations().get(0).getRefElementCollection()
                        .getItem(field -> finalBeParentField.getId().equals(field.getRefElementId()));
                Field schemaParentField = ((EntityType) bizField.getType()).getFields().stream()
                        .filter(field -> field.getId().equals(voParentField.getID())).findFirst().orElse(null);
                String schemaFieldId = beParentField.getMappingRelation().getMappingInfo(beBindingFieldId);
                Field schemaField = ((ObjectType) schemaParentField.getType()).getFields().stream()
                        .filter(field -> field.getOriginalId().equals(schemaFieldId)).findFirst().orElse(null);
                refObject.argvalue = schemaField;
                return schemaField.getId();
            default:
                throw new CAFRuntimeException("NOCODE", "BizFieldError", "不支持的业务字段嵌套层次，请联系技术人员", null);
        }
    }

    private GspMetadata getMetadata(String id, boolean isRuntime) {
        if (isRuntime) {
            return MetadataUtility.getInstance().getMetadataWithEnvironment(() -> {
                MetadataGetterParameter.GetterMetadataInfo getterMetadataInfo = new MetadataGetterParameter.GetterMetadataInfo();
                getterMetadataInfo.setId(id);
                return getterMetadataInfo;
            }, null, ExecuteEnvironment.Runtime, false);
        } else {
            MetadataGetterParameter metadataGetterParameter = MetadataGetterParameter.getNewInstance(id, null, MetadataTypeEnum.ViewModel);
            metadataGetterParameter.setTargetMetadataNotFoundMessage("更新表单schema，关联字段元数据找不到，请修正。对应字段元数据id为：" + id);
            return MetadataUtility.getInstance().getMetadataWithDesign(metadataGetterParameter);
        }
    }
}
